package cn.maihe.elg.operation.centers.epoint.handler;

import cn.maihe.elg.operation.centers.epoint.dto.EpointBaseRespDTO;
import cn.maihe.elg.operation.centers.epoint.enums.EpointRespCodeEnum;
import cn.maihe.elg.operation.centers.epoint.exception.EpointException;
import cn.maihe.elg.operation.centers.supports.annotation.CenterTradeService;
import cn.maihe.elg.operation.exception.CenterException;
import cn.maihe.elg.operation.exception.ExceptionUtils;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.CenterProviderEnum;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.SocketTimeoutException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * @Description 莆田公共资源服务中心-金融机构直开式
 * @Author Alan
 * @Date 2025/04/21
 */
@RestController
@RequestMapping(value = "pt/v1/center")
@Slf4j
public class PuTianCenterHandler {

    /**
     * 中心服务商
     */
    public static final CenterProviderEnum centerProvider = CenterProviderEnum.EPOINT;
    /**
     * 中心服务商的接口实现类
     */
    private final Map<String, EpointCenterTradeService> tradeServiceMap = new HashMap<>();
    /**
     * 能够使用与该中心服务商的 中心信息
     */
    public static final List<String> enableCenterNos = Lists.newArrayList(CenterNoEnum.PUTIAN.getCenterNo());

    public PuTianCenterHandler(@SuppressWarnings("rawtypes") final Collection<EpointCenterTradeService> baseCenterServices) {
        super();
        baseCenterServices.forEach(item -> {
            CenterTradeService ts = AnnotationUtils.findAnnotation(item.getClass(), CenterTradeService.class);
            if (centerProvider == ts.provider() && enableCenterNos.contains(ts.centerNo().getCenterNo())) {
                tradeServiceMap.put(ts.centerNo().getCenterNo() + ts.tradeType().name().toLowerCase(), item);
            }
        });
    }

    @PostMapping(value = "/{centerNo}/{orgCode}/{tradeType}", consumes = {"application/x-www-form-urlencoded"})
    public @ResponseBody
    DeferredResult<Object> service(@PathVariable("centerNo") String centerNo, @PathVariable("orgCode") String orgCode, @PathVariable("tradeType") final String tradeType, final HttpServletRequest req, final HttpServletResponse resp) {
        Map<String, Object> parameters = WebUtils.getParametersStartingWith(req, "");
        return this.doService(centerNo, orgCode, tradeType, req, resp, parameters, null);
    }

    @PostMapping(value = "/{centerNo}/{orgCode}/{tradeType}", consumes = {"application/json", "application/xml"})
    public @ResponseBody
    DeferredResult<Object> service(@PathVariable("centerNo") String centerNo, @PathVariable("orgCode") String orgCode, @PathVariable("tradeType") final String tradeType, @RequestBody final Map<String, Object> map, final HttpServletRequest req, final HttpServletResponse resp) {
        return this.doService(centerNo, orgCode, tradeType, req, resp, map, null);
    }


    @SuppressWarnings("unchecked")
    protected DeferredResult<Object> doService(String centerNo, String orgCode, String tradeType, final HttpServletRequest req, final HttpServletResponse resp, final Map<String, Object> parameters, final Map<String, MultipartFile> multipartFileMap) {

        DeferredResult<Object> dr = new DeferredResult<Object>();
        if (!this.tradeServiceMap.containsKey(centerNo + tradeType.toLowerCase())) {
            dr.setResult(buildRespException(EpointRespCodeEnum.FAILURE, "不支持的交易类型"));
            return dr;
        }
        CenterNoEnum centerNoEnum;
        try {
            centerNoEnum = CenterNoEnum.resolve(centerNo);
        } catch (Exception e) {
            log.error("暂不支持的交易中心[{}]:{}", centerNo, e.getMessage(), e);
            dr.setResult(buildRespException(EpointRespCodeEnum.FAILURE, "暂不支持的交易中心[" + centerNo + "]"));
            return dr;
        }

        CompletableFuture
                .supplyAsync(() -> {
                    try {
                        return this.tradeServiceMap.get(centerNo + tradeType.toLowerCase()).doService(centerNoEnum, orgCode, parameters, multipartFileMap);
                    } catch (Exception e) {
                        throw buildEpointException(e);
                    }
                })
                .whenCompleteAsync((baseResp, t) -> {
                    if (t != null) {
                        EpointException te = buildEpointException(t);
                        log.error("中心：{},交易类型：{},服务错误：{}", centerNoEnum.getCenterName(), tradeType, t.getMessage(), t);
                        EpointBaseRespDTO respDTO = buildRespException(te.getStatusEnum(), te.getMessage());
                        dr.setResult(respDTO);
                    } else {
                        dr.setResult(baseResp);
                    }
                    log.info("中心：{},交易类型：{},响应报文：{}", centerNoEnum.getCenterName(), tradeType, JSON.toJSONString(dr.getResult()));
                });
        return dr;
    }

    public EpointException buildEpointException(CenterException ce) {
        EpointRespCodeEnum respCodeEnum = EpointRespCodeEnum.FAILURE;
        //待优化明细
        if (ce.getInnerRespCode().isFailure()) {
            respCodeEnum = EpointRespCodeEnum.FAILURE;
        } else if (ce.getInnerRespCode().isException()) {
            respCodeEnum = EpointRespCodeEnum.FAILURE;
        } else if (ce.getInnerRespCode().isTimeOut()) {
            respCodeEnum = EpointRespCodeEnum.FAILURE;
        }
        return EpointException.of(respCodeEnum, ce.getMessage());
    }

    private EpointBaseRespDTO buildRespException(EpointRespCodeEnum statusEnum, String msg) {
        return EpointBaseRespDTO.of(statusEnum, msg);
    }

    private EpointException buildEpointException(Throwable t) {
        EpointException te = ExceptionUtils.isAssignableFrom(EpointException.class, t);
        if (te == null) {
            CenterException ce = ExceptionUtils.isAssignableFrom(CenterException.class, t);
            if (ce != null) {
                te = buildEpointException(ce);
            } else {
                SocketTimeoutException timeout = ExceptionUtils.isAssignableFrom(SocketTimeoutException.class, t);
                if (timeout != null) {
                    te = EpointException.of(EpointRespCodeEnum.FAILURE, "请求超时", t);
                } else {
                    te = EpointException.error("请求错误:" + t.getMessage(), t);
                }
            }
        }
        return te;
    }


}
